#ifndef __SOCK_H__
#define __SOCK_H__

#include <iostream>
#include <vector>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <cstring>
#include "log.h"
const unsigned int trunkSize = 256 * 1024;

const unsigned int PH_LEN = sizeof(unsigned int);//报头长度
const unsigned int MAX_DATABUFFSIZE = trunkSize;
const unsigned int MAX_DATASIZE = MAX_DATABUFFSIZE - PH_LEN;


//TODO 定义buffer
//处理协议 报头和正文分开
template <class T>
class Buffer
{
  public:
    Buffer()
      :maxsize_(0)
      ,offptr_(0)
      ,curptr_(0)
    {
      
    }
    ~Buffer(){};
    
    void reset()
    {
      offptr_ = 0;
      curptr_ = 0;
    }

    unsigned int maxsize()
    {
      return maxsize_;
    }
    unsigned int offptr()
    {
      return offptr_;
    }
    unsigned int curptr()
    {
      return curptr_;
    }

    unsigned int rd_size()
    {
      return curptr_ - offptr_;
    }
    unsigned int wr_size()
    {
      return maxsize_ - curptr_;
    }



    //只是声明不实现，特化的buffer必须实现对应函数，不然会编译报错
    void buf_reserve(unsigned int size);//对缓存中的数据重新整理，向缓冲中写入数据，如果缓存不足，重新调整缓存大小
    void put(const unsigned char* buf, const unsigned int size);//向缓冲区放数据
    unsigned char* wrbuf();//返回buf可写的起始地址
    unsigned char* rdbuf();//返回buf可读的起始地址
    void rd_flip(unsigned int size);//数据被使用后，对缓冲区进行调整
    void wr_flip(unsigned int size)
    {
      if(curptr_ + size > maxsize_)
      {
        curptr_ = maxsize_;  
      }
      else 
      {
        curptr_ += size;
      }
    }



  private:
    //缓冲区大小
    unsigned int maxsize_;
    //当前可读缓冲区起始位置
    unsigned int offptr_;
    //当前可写缓冲区起始位置
    unsigned int curptr_;
    //缓冲区
    T buffer_;

};

//动态缓存
typedef Buffer<std::vector<unsigned char> > DynamicBuffT;

template<>
DynamicBuffT::Buffer()
  :maxsize_(MAX_DATABUFFSIZE)
  ,offptr_(0)
  ,curptr_(0)
  ,buffer_(maxsize_)
{}

template<>
void DynamicBuffT::buf_reserve(unsigned int size)
{
  if(maxsize_ < curptr_)
  {
    std::cerr << "缓存异常" << std::endl;
  }

  if(wr_size() < size)
  {
    //需要扩容，扩容加trunkSize的整数倍
#define trunkCount(size) (((size) + trunkSize - 1) / trunkSize)
    int add = trunkCount(size) * trunkSize;

    maxsize_ += add;
    buffer_.resize(maxsize_);

  }
}

template<>
void DynamicBuffT::put(const unsigned char* buf, const unsigned int size)
{
  buf_reserve(size);

  memcpy(&buffer_[curptr_], buf, size);
  curptr_ += size;
}

template<>
void DynamicBuffT::rd_flip(unsigned int size)
{
   offptr_ += size;
   if(offptr_ > curptr_)
   {
     unsigned int tmp = curptr_ - offptr_;
     memmove(&buffer_[0], &buffer_[offptr_], tmp);
     offptr_ = 0;
     curptr_ = tmp;
   }
   else 
   {
     //数据都被取走了
     offptr_ = 0;
     curptr_ = 0;
   }
}

template<>
unsigned char* DynamicBuffT::wrbuf()
{
  if(curptr_ < maxsize_)
  {
    return &buffer_[curptr_];
  }
  return nullptr;
}

template<>
unsigned char* DynamicBuffT::rdbuf()
{
  if(offptr_ < maxsize_)
  {
    return &buffer_[offptr_];
  }
  return nullptr;
}

//静态缓存
typedef Buffer<unsigned char [MAX_DATABUFFSIZE]> StaticBufferT;

template<>
StaticBufferT::Buffer()
  :maxsize_(MAX_DATABUFFSIZE)
  ,offptr_(0)
  ,curptr_(0)
{}

template<>
void StaticBufferT::buf_reserve(unsigned int size)
{
  //定长，不扩容   
}

template<>
void StaticBufferT::put(const unsigned char* buf, const unsigned int size)
{
  unsigned int add_size = size;
  if(curptr_ + size > maxsize_)
  {
    add_size = maxsize_ - curptr_;
  }
  
  memcpy(&buffer_[curptr_], buf, add_size);
  curptr_ += add_size;
}

template<>
void StaticBufferT::rd_flip(unsigned int size)
{
   offptr_ += size;
   if(offptr_ > curptr_)
   {
     unsigned int tmp = curptr_ - offptr_;
     memmove(&buffer_[0], &buffer_[offptr_], tmp);
     offptr_ = 0;
     curptr_ = tmp;
   }
   else 
   {
     //数据都被取走了
     offptr_ = 0;
     curptr_ = 0;
   }
}

template<>
unsigned char* StaticBufferT::wrbuf()
{
  if(curptr_ < maxsize_)
  {
    return &buffer_[curptr_];
  }
  return nullptr;
}

template<>
unsigned char* StaticBufferT::rdbuf()
{
  if(offptr_ < maxsize_)
  {
    return &buffer_[offptr_];
  }
  return nullptr;
}

#define SOCKLISTENNUM 5
class SockOpt
{
public:
    static int Socket()
    {
        return socket(AF_INET, SOCK_STREAM, 0); 
    }

    static int Connect(int sockfd, const char* ip, size_t port)
    {
      struct sockaddr_in peer;
      peer.sin_port = htons(port);
      peer.sin_family = AF_INET;
      peer.sin_addr.s_addr = inet_addr(ip);
      return connect(sockfd, (struct sockaddr*)&peer, sizeof(peer));
    }

    static unsigned int getMessageInBuffer(void *strCmd, int strlen)
    {
      if(rev_buffer_.rd_size() >= PH_LEN)
      {
        //说明里面有数据
        //每次读取一整条数据，报头保存的是正文长度
        unsigned int recordLen = PH_LEN + (*(unsigned int*)rev_buffer_.rdbuf());
        if(rev_buffer_.rd_size() >= recordLen)
        {
          unsigned int cmdLen = recordLen - PH_LEN;
          if(cmdLen > (unsigned int)strlen)
          {
            Logger::error("getmessage err, len:%u, strlen:%d", cmdLen, strlen);
            cmdLen = strlen;
          }
          unsigned char* cmd = (unsigned char*)strCmd;
          unsigned char* bf = rev_buffer_.rdbuf();
          //去掉报头
          memcpy(cmd, &bf[PH_LEN], cmdLen);
          //设置curPtr
          rev_buffer_.rd_flip(recordLen);
          return cmdLen;
        }
      }
      return 0;
    }
    

    static int RecvCmd(void* strCmd, int strlen,  int sockfd, bool wait = false)
    {
      //先从缓存里面读
      unsigned int len = getMessageInBuffer(strCmd ,strlen);
      if(len)
      {
        return len;
      }
      //没有再去recv
      do{

        ssize_t num = recv(sockfd, rev_buffer_.wrbuf(), rev_buffer_.wr_size(), 0);
        if(num < 0 || (num == 0 && !wait))
          return num;

        rev_buffer_.wr_flip(num);
        return getMessageInBuffer(strCmd ,strlen);

      }while(true);

    }

    static int SendCmd(void* strCmd, unsigned int cmdLen, int sockfd, bool buffer = false)
    {
      int cmdSize = 0;
      if(cmdLen > MAX_DATASIZE)
      {
        Logger::error("消息越界，len:%u", cmdLen);
      }

     
      //直接发送出去
      StaticBufferT cmdQueue;
      cmdSize = cmdLen + PH_LEN;
      cmdQueue.buf_reserve(cmdSize);
      unsigned char* cmd = (unsigned char*)strCmd;
      bcopy(cmd, &(cmdQueue.wrbuf()[PH_LEN]), cmdSize);
      //报头保存正文长度
      *((unsigned int*)cmdQueue.wrbuf()) = cmdLen;
      cmdQueue.wr_flip(cmdSize);
      
      if(buffer)
      {
       snd_buffer_.put(cmdQueue.rdbuf(), cmdQueue.rd_size());
      }
      else 
      {
       int offset = 0;
       do{
         int ret = send(sockfd, cmdQueue.rdbuf(), cmdQueue.rd_size(), 0);

         if(ret < 0)
         {
           return ret;
         }
         offset += ret;
         
       }while(offset < cmdSize);
      }
      return cmdSize;
    }
private:
    //消息缓存
    static DynamicBuffT rev_buffer_; 
    static DynamicBuffT snd_buffer_;
};

DynamicBuffT SockOpt::rev_buffer_;
DynamicBuffT SockOpt::snd_buffer_;

#endif
